#include <carbon/core/error.h>

CARBON_NS_BEGIN

Error & Error::operator=(Error && other) noexcept {
    if ( this != &other) {
        cause_ = std::move(other.cause_);
    }
    return *this;
}

Error & Error::push(const char * file, int line, int code, std::string && msg) {
    const char * p = strrchr(file, CARBON_FILE_SEP);
    if ( p == nullptr ) p = file;
    else p += 1;

    char posbuf[256];
    snprintf(posbuf, sizeof(posbuf), "%s:%d", p, line);
    auto cause = std::make_unique<Cause>(Cause{code, std::move(msg), posbuf});
    if (cause_) cause->cause = std::move(cause_);
    cause_ = std::move(cause);
    return *this;
}

String Error::toString() const {
    if ( !cause_ ) return String();

    std::ostringstream oss;
    oss << *this;
    return oss.str();
}

std::ostream & operator<<(std::ostream & os, const Error & error) {
    if ( !error ) return os;

    os << "Error at " << error.cause_->pos << ": " << error.cause_->code<<", "<<error.cause_->msg<<std::endl;

    auto * p_cause = error.cause_->cause.get();
    while ( p_cause ) {
        os << "  Caused by " << p_cause->pos << ": " << p_cause->code<<" "<<p_cause->msg<<std::endl;
        p_cause = p_cause->cause.get();
    }
    return os;
}

std::string buildSystemErrorMesage(int error_code, const char * prefix)
{
    std::string msg;
    msg.reserve(128);
    msg.append(1, '[').append(prefix).append(1, ']').append(" errno: ").append(std::to_string(error_code))
       .append(" msg: ").append(strerror(error_code));
    return msg;
}


CARBON_NS_END
